import os
import re
import argparse
from datetime import datetime
from test_tools.class_excel import Reader, Writer
from common.inter_keys import HTTP
from common.config_loader import ConfigLoader
from common.html_reporter import HTMLReporter
from common.summary_generator import SummaryGenerator
from test_tools.logger import Logger


class FinalTestExecutorV3:
    def __init__(self, env='a'):
        self.http = None
        self.writer = None
        self.reader = Reader()
        self.relations = {}
        self.summary_data = {}
        self.summary_sheet_name = "测试汇总"
        self.case_logs = []
        self.logger = Logger()
        self.env = env
        self.config_loader = None
        self.test_data = {}
        self.base_url = ""
        self.html_reporter = HTMLReporter(self.logger)
        self.report_path = None
        self.summary_generator = None

    def execute(self, file_name, sheet_name=None):
        """执行测试入口"""
        try:
            file_path = os.path.abspath(f"./test_cases/{file_name}")
            if not os.path.exists(file_path):
                self.logger.error(f"测试案例文件不存在: {file_path}")
                return

            # 加载环境配置
            self.config_loader = ConfigLoader(self.env)
            self.test_data = self.config_loader.test_data
            self.base_url = self.config_loader.base_url  # 保存基础url

            self.reader.open_excel(file_path)
            result_file = os.path.abspath(f"./test_results/result_{file_name}")
            self.writer = Writer()
            self.writer.copy_open(file_path, result_file)
            self.summary_generator = SummaryGenerator(self.writer)

            self._init_summary()
            sheets = [sheet_name] if sheet_name else self._get_executable_sheets()

            for sheet in sheets:
                self._process_sheet(sheet)

            self.summary_generator.generate_summary(self.summary_data)
            self.writer.save_close()
            self.logger.info(f"测试结果已保存至: {result_file}")

            # 生成HTML报告
            self.html_reporter.generate_report(self.summary_data, self.case_logs)
        except Exception as e:
            self.logger.error(f"执行异常: {str(e)}")
            import traceback
            self.logger.error(traceback.format_exc())

    def _init_summary(self):
        """初始化汇总数据结构"""
        sheets = self._get_executable_sheets()
        for sheet in sheets:
            self.summary_data[sheet] = {
                'case_total': 0,
                'case_pass': 0,
                'case_fail': 0,
                'start_time': datetime.now()
            }

    def _get_executable_sheets(self):
        """获取需要执行的sheet列表（排除汇总sheet）"""
        return [s for s in self.reader.get_sheets()
                if s != self.summary_sheet_name]

    def _process_sheet(self, sheet_name):
        """处理单个sheet"""
        self.reader.set_sheet(sheet_name)
        self.writer.set_sheet(sheet_name)
        lines = self.reader.readline()

        self.http = HTTP(self.writer, self.test_data)
        self.http.relations = self.relations
        self.http.url = self.base_url

        # 执行所有基础设置步骤
        self._execute_setup_steps(lines)

        current_group = "未分组"
        case_ranges = []
        start_row = 0
        current_case = None

        # 遍历行识别用例和分组
        for idx, line in enumerate(lines):
            if idx == 0: continue  # 跳过标题行

            # 处理分组（A列非空）
            if line[0]:
                current_group = line[0]
                continue

            # 识别用例开始（C列非空）
            if line[2]:
                if current_case:
                    case_ranges.append((current_group, current_case, start_row, idx - 1))
                current_case = line[2]
                start_row = idx

        if current_case:
            case_ranges.append((current_group, current_case, start_row, len(lines) - 1))

        # 更新用例总数
        self.summary_data[sheet_name]['case_total'] = len(case_ranges)
        # 执行测试用例
        for group, case_name, start, end in case_ranges:
            self._execute_case(sheet_name, group, case_name, lines, start, end)

    def _execute_setup_steps(self, lines):
        """执行基础设置步骤"""
        in_setup = False
        for idx, line in enumerate(lines):
            if idx == 0: continue

            # 进入基础设置区块
            if line[1] == "基础设置":
                self.logger.info(f"⚙ 开始执行基础设置步骤...")
                in_setup = True
                continue

            # 执行基础设置步骤
            if in_setup:
                # 遇到下一个分组时退出
                if line[1] or line[2]:
                    in_setup = False
                    continue

                if line[4]:  # 存在关键字
                    self._execute_step(line, idx, is_setup=True)

    def _execute_case(self, sheet_name, group, case_name, lines, start, end):
        """执行单个测试用例"""
        case_status = "PASS"
        case_log = {
            'id': f"{sheet_name}_{case_name}",
            'sheet': sheet_name,
            'group': group,
            'name': case_name,
            'status': case_status,
            'steps': [],
            'start_time': datetime.now(),
            'end_time': None,
            'duration': 0
        }

        self.logger.info(f"\n▶ 开始执行用例: {case_name} [Sheet: {sheet_name}]")

        for row_idx in range(start, end + 1):
            line = lines[row_idx]
            if not line[3]: continue  # D列为空则跳过

            step_status = self._execute_step(line, row_idx)
            case_log['steps'].append(step_status)

            if step_status['status'] != "pass":
                case_status = "FAIL"

        # 更新用例状态
        case_row = self._find_case_title_row(lines, start)
        color = "3" if case_status == "PASS" else "2"
        self.writer.write(case_row, 8, case_status, color)

        # 更新统计
        if case_status == "PASS":
            self.summary_data[sheet_name]['case_pass'] += 1
        else:
            self.summary_data[sheet_name]['case_fail'] += 1

        # 记录日志
        case_log.update({
            'status': case_status,
            'end_time': datetime.now(),
            'duration': (datetime.now() - case_log['start_time']).total_seconds()
        })
        self.case_logs.append(case_log)

    def _execute_step(self, line, row_idx, is_setup=False):
        """执行单个步骤"""
        step_desc = line[3]
        keyword = line[4]
        args = [arg for arg in line[5:8] if arg]
        status = "pass"
        result_msg = ""
        actual_result = ""

        try:
            if not keyword:
                return {
                    'step': step_desc,
                    'status': 'skip',
                    'msg': '无关键字',
                    'actual': actual_result
                }

            # 特殊处理set_url: 使用配置的URL
            if keyword == "set_url":
                # 直接使用配置的url, 不再从Excel获取
                args = [self.base_url]
                # 将实现URL写入Excel输入列(便于查看)
                self.writer.writer(row_idx, 5, self.base_url)

            self.http.r = row_idx
            method = getattr(self.http, keyword)

            # 处理环境测试数据替换
            processed_args = []
            for arg in args:
                if arg and '{{env.' in arg:
                    placeholders = re.findall(r'{{env\.(.*?)}}', arg)
                    for ph in placeholders:
                        try:
                            # 支持多级路径: env.customers.cust_name
                            keys = ph.split('.')
                            value = self.test_data
                            for k in keys:
                                value = value[k]
                            # 替换占位符
                            arg = arg.replace('{{env.' + ph + '}}', str(value))
                        except KeyError:
                            raise ValueError(f"测试数据路径不存在: env.{ph}")
                processed_args.append(arg)
            result = method(*processed_args)

            # 获取实际结果（J列）
            actual_result = line[9] if len(line) > 9 else ""

            if not result:
                status = "fail"
                result_msg = "断言失败"
        except Exception as e:
            status = "fail"
            result_msg = f"{type(e).__name__}: {str(e)}"
            actual_result = str(e)
            if not is_setup:
                self.logger.error(f"    ! 步骤失败: {result_msg}")

        # 写入Excel结果
        self.writer.write(row_idx, 8, status, "3" if status == "pass" else "2")
        self.writer.write(row_idx, 9, result_msg[:1024])

        return {
            'step': step_desc,
            'status': status,
            'msg': result_msg,
            'actual': actual_result
        }

    def _find_case_title_row(self, lines, start_row):
        row = start_row
        while row >= 0 and not lines[row][2]:
            row -= 1
        return row

if __name__ == "__main__":
    parser = argparse.ArgumentParser(description="V3版测试执行器")
    parser.add_argument("-f", "--file", required=True, help="测试用例文件路径")
    parser.add_argument("-s", "--sheet", help="指定执行的sheet名称")
    parser.add_argument("-d", "--dir", help="批量执行目录")
    parser.add_argument("-e", "--env", required=True, choices=['a', 'c', 'f'], help="测试环境: -a, -c, -f")
    args = parser.parse_args()

    executor = FinalTestExecutorV3()
    if args.dir:
        for fname in os.listdir(args.dir):
            if fname.startswith("HTTP接口用例") and fname.endswith(".xlsx"):
                executor.execute(os.path.join(args.dir, fname), args.sheet)
    else:
        executor.execute(args.file, args.sheet)